home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cpp_libs / cool / cool.lha / ice / pisces / rcs / rcsutil.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-09-04  |  13.3 KB  |  509 lines

  1. /*
  2.  *                     RCS utilities
  3.  */
  4. #ifndef lint
  5. static char rcsid[]= "$Id: rcsutil.c,v 1.3 91/02/11 15:43:12 fontana Exp $ Purdue CS";
  6. #endif
  7.  
  8. /* Copyright (C) 1982, 1988, 1989 Walter Tichy
  9.    Distributed under license by the Free Software Foundation, Inc.
  10.  
  11. This file is part of RCS.
  12.  
  13. RCS is free software; you can redistribute it and/or modify
  14. it under the terms of the GNU General Public License as published by
  15. the Free Software Foundation; either version 1, or (at your option)
  16. any later version.
  17.  
  18. RCS is distributed in the hope that it will be useful,
  19. but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21. GNU General Public License for more details.
  22.  
  23. You should have received a copy of the GNU General Public License
  24. along with RCS; see the file COPYING.  If not, write to
  25. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  26.  
  27. Report problems and direct all questions to:
  28.  
  29.     rcs-bugs@cs.purdue.edu
  30.  
  31. */
  32.  
  33.  
  34.  
  35.  
  36. /* $Log:    rcsutil.c,v $
  37.  * Revision 1.3  91/02/11  15:43:12  fontana
  38.  * Changed run function to use execvp instead of execv
  39.  * 
  40.  * Revision 1.2  90/05/21  14:05:22  neath
  41.  * modified signal handling
  42.  * 
  43.  * Revision 1.1  90/05/21  13:43:12  neath
  44.  * Initial revision
  45.  * 
  46.  * Revision 4.6  89/05/01  15:13:40  narten
  47.  * changed copyright header to reflect current distribution rules
  48.  * 
  49.  * Revision 4.5  88/11/08  16:01:02  narten
  50.  * corrected use of varargs routines
  51.  * 
  52.  * Revision 4.4  88/11/08  12:00:28  narten
  53.  * changes from  eggert@sm.unisys.com (Paul Eggert)
  54.  * 
  55.  * Revision 4.4  88/08/09  19:13:24  eggert
  56.  * Check for memory exhaustion.
  57.  * Permit signal handlers to yield either 'void' or 'int'; fix oldSIGINT botch.
  58.  * Use execv(), not system(); yield exit status like diff(1)'s.
  59.  * 
  60.  * Revision 4.3  87/10/18  10:40:22  narten
  61.  * Updating version numbers. Changes relative to 1.1 actually
  62.  * relative to 4.1
  63.  * 
  64.  * Revision 1.3  87/09/24  14:01:01  narten
  65.  * Sources now pass through lint (if you ignore printf/sprintf/fprintf 
  66.  * warnings)
  67.  * 
  68.  * Revision 1.2  87/03/27  14:22:43  jenkins
  69.  * Port to suns
  70.  * 
  71.  * Revision 1.1  84/01/23  14:50:43  kcs
  72.  * Initial revision
  73.  * 
  74.  * Revision 4.1  83/05/10  15:53:13  wft
  75.  * Added getcaller() and findlock().
  76.  * Changed catchints() to check SIGINT for SIG_IGN before setting up the signal
  77.  * (needed for background jobs in older shells). Added restoreints().
  78.  * Removed printing of full RCS path from logcommand().
  79.  * 
  80.  * Revision 3.8  83/02/15  15:41:49  wft
  81.  * Added routine fastcopy() to copy remainder of a file in blocks.
  82.  *
  83.  * Revision 3.7  82/12/24  15:25:19  wft
  84.  * added catchints(), ignoreints() for catching and ingnoring interrupts;
  85.  * fixed catchsig().
  86.  *
  87.  * Revision 3.6  82/12/08  21:52:05  wft
  88.  * Using DATEFORM to format dates.
  89.  *
  90.  * Revision 3.5  82/12/04  18:20:49  wft
  91.  * Replaced SNOOPDIR with SNOOPFILE; changed addlock() to update
  92.  * lockedby-field.
  93.  *
  94.  * Revision 3.4  82/12/03  17:17:43  wft
  95.  * Added check to addlock() ensuring only one lock per person.
  96.  * Addlock also returns a pointer to the lock created. Deleted fancydate().
  97.  *
  98.  * Revision 3.3  82/11/27  12:24:37  wft
  99.  * moved rmsema(), trysema(), trydiraccess(), getfullRCSname() to rcsfnms.c.
  100.  * Introduced macro SNOOP so that snoop can be placed in directory other than
  101.  * TARGETDIR. Changed %02d to %.2d for compatibility reasons.
  102.  *
  103.  * Revision 3.2  82/10/18  21:15:11  wft
  104.  * added function getfullRCSname().
  105.  *
  106.  * Revision 3.1  82/10/13  16:17:37  wft
  107.  * Cleanup message is now suppressed in quiet mode.
  108.  */
  109.  
  110.  
  111.  
  112.  
  113. #include <sys/types.h>
  114. #include <sys/stat.h>
  115. #include <signal.h>
  116. #include "rcsbase.h"
  117. #include <pwd.h>
  118. #include <varargs.h>
  119.  
  120. #if defined(USG) || defined(V4_2BSD)
  121. #include <fcntl.h>
  122. #endif
  123.  
  124. #ifndef V4_2BSD
  125. #define vfork fork
  126. #endif
  127.  
  128. extern char * bindex();
  129. extern FILE * finptr;
  130. extern char * RCSfilename;
  131. extern char * getlogin();
  132. extern struct passwd *getpwuid();
  133. extern char * malloc();
  134.  
  135.  
  136. char * talloc(size)
  137. unsigned size;
  138. {
  139.     char * p;
  140.     if (!(p = malloc(size))) {
  141.         faterror("out of memory");
  142.     }
  143.     return p;
  144. }
  145.  
  146.  
  147.  
  148. char * getcaller()
  149. /* Function: gets the callers login from his uid.
  150.  * If the uid is root, tries to get the true login with getlogin().
  151.  */
  152. {       char * name;
  153.     int uid;
  154.     uid=getuid();
  155.     if (uid==0) {
  156.         /* super user; try getlogin() to distinguish */
  157.         name = getlogin();
  158.         if (name!=nil && *name!='\0')
  159.             return name;
  160.     }
  161.     return(getpwuid(uid)->pw_name);
  162. }
  163.  
  164.  
  165.  
  166. struct hshentry * findlock(who,delete)
  167. char * who; int delete;
  168. /* Finds the first lock held by who and returns a pointer
  169.  * to the locked delta; also removes the lock if delete==true.
  170.  * Returns nil if there is no lock held by who.
  171.  */
  172. {
  173.         register struct lock * next, * trail;
  174.         struct lock dummy;
  175.  
  176.         dummy.nextlock=next=Locks;
  177.         trail = &dummy;
  178.         while (next!=nil) {
  179.                 if(strcmp(who,next->login)==0) break; /*found a lock*/
  180.                 trail=next;
  181.                 next=next->nextlock;
  182.         }
  183.         if (next!=nil) {
  184.         /* found one */
  185.         if (delete) {
  186.             /* delete it */
  187.             trail->nextlock=next->nextlock;
  188.             Locks=dummy.nextlock;
  189.             next->delta->lockedby=nil; /* reset locked-by */
  190.         }
  191.                 return next->delta;
  192.         } else  return nil;
  193. }
  194.  
  195.  
  196.  
  197.  
  198.  
  199.  
  200.  
  201. struct lock * addlock(delta,who)
  202. struct hshentry * delta; char * who;
  203. /* Given a delta, addlock checks whether
  204.  * the delta is locked by somebody other than who.
  205.  * If so, an error message is printed, and false returned.
  206.  * If the delta is not reserved at all, a lock for it is added,
  207.  * and a pointer for the lock returned.
  208.  */
  209. {
  210.         struct lock * next;
  211.  
  212.         next=Locks;
  213.         while (next!=nil) {
  214.                 if (cmpnum(delta->num,next->delta->num)==0) {
  215.                         if (strcmp(who,next->login)==0)
  216.                                 return next;
  217.                                 /* lock exists already */
  218.                         else {
  219.                                 error("revision %s already locked by %s",
  220.                                       delta->num, next->login);
  221.                                 return false;
  222.                         }
  223.                 } else {
  224.                         if (strcmp(who,next->login)==0) {
  225.                                 error("you already locked %s; only one lock allowed per person.",
  226.                                        next->delta->num);
  227.                                 return false;
  228.                         } else {
  229.                                 next=next->nextlock;
  230.                         }
  231.                 }
  232.         }
  233.         /* not found; set up new lockblock */
  234.         next= (struct lock *) talloc(sizeof (struct lock));
  235.         delta->lockedby=next->login=who;
  236.         next->delta= delta;
  237.         next->nextlock=Locks;
  238.         Locks=next;
  239.         return next;
  240. }
  241.  
  242.  
  243.  
  244. int addsymbol(delta,name,rebind)
  245. struct hshentry * delta; char * name; int rebind;
  246. /* Function: adds a new symbolic name and associates it with node delta.
  247.  * If name already exists and rebind is true, the name is associated
  248.  * with the new delta; otherwise, an error message is printed and
  249.  * false returned. Returns true it successful.
  250.  */
  251. {       register struct assoc * next;
  252.         next=Symbols;
  253.         while (next!=nil) {
  254.                 if (strcmp(name,next->symbol)==0) {
  255.                         if (rebind) {
  256.                                 next->delta=delta;
  257.                                 return true;
  258.                         } else {
  259.                                 error("symbolic name %s already bound to %s",
  260.                                         name,next->delta->num);
  261.                                 return false;
  262.                         }
  263.                 } else  next = next->nextassoc;
  264.         }
  265.         /* not found; insert new pair. */
  266.         next = (struct assoc *) talloc(sizeof(struct assoc));
  267.         next->symbol=name;
  268.         next->delta=delta;
  269.         next->nextassoc=Symbols;
  270.         Symbols = next;
  271.         return true;
  272. }
  273.  
  274.  
  275.  
  276.  
  277. int checkaccesslist(who)
  278. char * who;
  279. /* function: Returns true if who is the superuser, the owner of the
  280.  * file, the access list is empty, or who is on the access list.
  281.  * Prints an error message and returns false otherwise.
  282.  */
  283. {
  284.         register struct access * next;
  285.         struct stat statbuf;
  286.  
  287.         if ((AccessList==nil) || (strcmp(who,"root")==0))
  288.                 return true;
  289.  
  290.         next=AccessList;
  291.         do {
  292.                 if (strcmp(who,next->login)==0)
  293.                         return true;
  294.                 next=next->nextaccess;
  295.         } while (next!=nil);
  296.  
  297.         VOID fstat(fileno(finptr),&statbuf);  /* get owner of file */
  298.         if (getuid() == statbuf.st_uid) return true;
  299.  
  300.         error("User %s not on the access list",who);
  301.         return false;
  302. }
  303.  
  304.  
  305. static SIGNAL_TYPE catchsig(s)
  306. {
  307.     ignoreints();
  308.         diagnose("\nRCS: cleaning up\n");
  309.         VOID cleanup();
  310.     exit(2);
  311. #ifdef lint
  312.     catchsig(s);
  313. #endif
  314. }
  315.  
  316. static sig[] = {SIGINT,SIGHUP,SIGQUIT,SIGPIPE,SIGTERM};
  317. #define SIGS (sizeof(sig)/sizeof(*sig))
  318. static SIGNAL_TYPE (*catcher[SIGS])();
  319.   
  320.   void catchints()
  321.   {
  322.     register i;
  323.     for (i=SIGS; 0<=--i; )
  324.         if (signal(sig[i], SIG_IGN) == SIG_IGN)
  325.         catcher[i] = SIG_IGN;
  326.         else    
  327.             catcher[i] = catchsig;
  328.     restoreints();
  329.   }
  330.  
  331.   void ignoreints()
  332.   {
  333.     register i;
  334.     for (i=SIGS; 0<=--i; )
  335.         VOID signal(sig[i], SIG_IGN);
  336.   }
  337.  
  338. void restoreints()
  339. {
  340.     register i;
  341.     for (i=SIGS; 0<=--i; )
  342.         if (catcher[i] != SIG_IGN)
  343.             VOID signal(sig[i], catcher[i]);
  344. }
  345.  
  346. fastcopy(inf,outf)
  347. FILE * inf, * outf;
  348. /* Function: copies the remainder of file inf to outf. First copies the
  349.  * rest that is in the IO-buffer of inf character by character, and then
  350.  * copies the remainder in blocks.
  351.  */
  352. {       char buf[BUFSIZ];
  353.         register int rcount, wcount;
  354.  
  355.         /* write the rest of the buffer to outf */
  356.         while ((--inf->_cnt)>=0) {
  357.                 VOID putc(*inf->_ptr++&0377,outf);
  358.         }
  359.         if (fflush(outf) == EOF) {
  360.         writeerror();
  361.     }
  362.  
  363.         /*now read the rest of the file in blocks*/
  364.         while ((rcount=read(fileno(inf),buf,BUFSIZ))>0) {
  365.                 wcount=write(fileno(outf),buf,rcount);
  366.                 if (wcount!=rcount) {
  367.                     writeerror();
  368.                 }
  369.         }
  370. }
  371.  
  372.  
  373.  
  374.  
  375.  
  376.  
  377. #ifdef SNOOPFILE
  378.  
  379. #include "time.h"
  380. extern struct tm* localtime();
  381. extern long time();
  382.  
  383. logcommand(commandname,delta, sequence,login)
  384. char* commandname; struct hshentry * delta, * sequence[];char * login;
  385. /* Function: start a process to write the file that
  386.  * logs the RCS command.
  387.  * Each line in the log file contains the following information:
  388.  * operation, revision(r), backward deltas applied(b), forward deltas applied(f),
  389.  * total deltas present(t), creation date of delta(d), date of operation(o),
  390.  * login of caller, RCS file name.
  391.  */
  392. {
  393.         char logline[200];
  394.         char curdate[datelength];
  395.     char *inoutargs[5];
  396.         register int i, backward, forward;
  397.         long clock;
  398.         struct tm * tm;
  399.  
  400.         clock=time((long *)0);
  401.         tm=localtime(&clock);
  402.  
  403.         VOID sprintf(curdate,DATEFORM,
  404.                 tm->tm_year, tm->tm_mon+1, tm->tm_mday,
  405.                 tm->tm_hour, tm->tm_min, tm->tm_sec);
  406.  
  407.         i= backward=forward=0;
  408.         while(sequence[i]!=nil) {  /* count deltas to be applied*/
  409.         if (countnumflds(sequence[i]->num) == 2)
  410.                 backward++;  /* reverse delta */
  411.         else    forward++;   /* branch delta  */
  412.         i++;
  413.         }
  414.     VOID sprintf(logline,"%s %10sr %3db %3df %3dt %sc %so %s %s",
  415.         commandname,delta->num,backward,forward,TotalDeltas,delta->date,
  416.         curdate,login,bindex(getfullRCSname(),'/'));
  417.     inoutargs[0] = nil;
  418.     inoutargs[1] = nil;
  419.     inoutargs[2] = SNOOP;
  420.     inoutargs[3] = logline;
  421.     inoutargs[4] = nil;
  422.     VOID run_back(inoutargs);
  423. }
  424. #endif
  425.  
  426.  
  427. static int fdreopen(fd, file, flags, mode)
  428.     char *file;
  429. {
  430.     int newfd;
  431.     VOID close(fd);
  432.     newfd = flags==-1 ? creat(file,mode) : open(file,flags,mode);
  433.     if (newfd < 0  ||  newfd == fd)
  434.         return newfd;
  435. #ifdef F_DUPFD
  436.     fd = fcntl(newfd, F_DUPFD, fd);
  437. #else
  438.     fd = dup2(newfd, fd);
  439. #endif
  440.     VOID close(newfd);
  441.     return fd;
  442. }
  443.  
  444. static void tryopen(fd,file,flags)
  445.     char *file;
  446. {
  447.     if (file  &&  fdreopen(fd,file,flags,0600) != fd) {
  448.         VOID write(fileno(stderr), file, strlen(file));
  449.         VOID write(fileno(stderr), ": cannot open\n", 14);
  450.         _exit(2);
  451.     }
  452. }
  453.  
  454. /*
  455. /* Run in the background a command specified by the strings in 'inoutargs'.
  456. /* inoutargs[0], if nonnil, is the name of the input file.
  457. /* inoutargs[1], if nonnil, is the name of the output file.
  458. /* inoutargs[2..] form the command to be run in the background.
  459. /*/
  460. static int run_back(inoutargs)
  461.     register char **inoutargs;
  462. {
  463.     int pid;
  464.     if (fflush(stdout) == EOF  ||  fflush(stderr) == EOF)
  465.         return -1;
  466.     if (!(pid = vfork())) {
  467.         tryopen(fileno(stdin), inoutargs[0], 0);
  468.         tryopen(fileno(stdout), inoutargs[1], -1);
  469.         VOID execvp(inoutargs[2], &inoutargs[2]);
  470.         inoutargs[1] = "/bin/sh";
  471.         VOID execvp(inoutargs[1], &inoutargs[1]);
  472.         VOID write(fileno(stderr), "/bin/sh: not found\n", 19);
  473.         _exit(2);
  474.     }
  475.     return pid;
  476. }
  477.  
  478. #define CARGSMAX 20
  479. /*
  480. /* Run a command.
  481. /* The first two arguments are the input and output files (if nonnil);
  482. /* the rest specify the command and its arguments.
  483. /*/
  484. int run(va_alist)
  485.     va_dcl
  486. {
  487.     va_list ap;
  488.     int pid, wstatus, w;
  489.     char *rgargs[CARGSMAX];
  490.     register i = 0;
  491.     va_start(ap);
  492.     rgargs[0] = va_arg(ap, char *);
  493.     rgargs[1] = va_arg(ap, char *);
  494.     for (i =2; i< CARGSMAX; i++) {
  495.         rgargs[i] = va_arg(ap, char *);
  496.         if (rgargs[i] == NULL)
  497.         break;
  498.     }
  499.     va_end(ap);
  500.     pid = run_back(rgargs);
  501.     if (pid < 0)
  502.         return pid;
  503.     for (;;)
  504.         if ((w = wait(&wstatus)) < 0)
  505.             return w;
  506.         else if (w == pid)
  507.             return wstatus;
  508. }
  509.